﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Collections;
namespace p20_15
{
    class Program
    {
        static void Main(string[] args)
        {
 
            int ow = 20;        // 观察窗大小
            int threshold = 15; // 观察窗内判决门限
 
            double p = 0.9;
            double result = 0;
            double total = 0;
            for (int outer = -5; outer <= 10; outer++)
            {
                result = CaculateP(ow, threshold, outer, p);
                total += result;
                Console.WriteLine($"p(A{ ow-threshold + outer}) : {result.ToString("0.000000")} total:{total.ToString("0.000000")}");
               
            }
            Console.WriteLine("End..");
            Console.ReadLine();
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="v">值</param>
        /// <param name="len">右侧被计算的位的个数</param>
        /// <returns></returns>
        static int OneCount(UInt32 v, int len)
        {
            int cnt = 0;
            
            for(int k=0;k<len;k++)
            {
                if((v&0x01)!=0)
                {
                    cnt++;
                }
                v >>= 1;
            }

            return cnt;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="ow">观察窗大小</param>
        /// <param name="threshold">观察窗内判决门限</param>
        /// <param name="outerCnt">右侧移除的个数,可以是负数</param>
        /// <param name="p">判决1的概率</param>
        /// <returns></returns>
        static double CaculateP(int ow, int threshold, int outerCnt, double p)
        {
            UInt32 value = 0;
            int cnt = 0;
            double result = 0;

            if (threshold > ow)
                throw new Exception("门限不应大于窗口大小");
            if (outerCnt < threshold - ow)
                throw new Exception("OuterCnt参数过小");

            value = (UInt32)(1 << (ow + outerCnt - 1));/*+outerCnt*/
            UInt32 endValue = UInt32.MaxValue >> (32 - ow - outerCnt);

            for (; value <= endValue; value++)
            {
                int k = 0;
                for ( ; k < outerCnt; k++)
                {
                    cnt = OneCount(value >> k, ow);
                    if (cnt >= threshold)
                        break;
                }
                if (k == outerCnt || outerCnt<0)
                {
                    cnt = OneCount(outerCnt<0?value:value >> outerCnt, ow);
                    if (cnt == threshold)
                    {
                        cnt = OneCount(value, (ow + outerCnt));
                        result += Math.Pow(p, cnt) * Math.Pow((1 - p), ow + outerCnt - cnt);
                    }
                }
            }
            return result;
        }

    }
}
